﻿//-----------------------------------------------------------------------
// <copyright file="xxxxxxx.cs" comapny="n.a.">
//     Copyright Dave999. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "To be returned to .")]
[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1601:PartialClassMustBeDocumented", Justification = "To be returned to .")]
/*
    Prevent colours and font style from paste text source.
    This form is obsolete as the query window has moved into the main application
*/

namespace DbView
{
	using System;
	using System.Data;
	using System.Drawing;
	using System.Windows.Forms;

	public partial class AdhocQueryWindow : Form
	{
		private Rectangle holdBounds;

		DbViewDriver.IDataSource dataSource; // hold the datasource otherwise no queries will get done
		string connectionString;			// hold original connection string in place when the window was created.

		public AdhocQueryWindow(ConnectionInfo connInfo, DbViewDriver.IDataSource dataSource)
		{
			InitializeComponent();
			/*
			Note: the decision is to freeze the connection for each adhoc query window
			rather than obtain the current connection string from the model. This is 
			in order to minimise accidental changes to the wrong database.
			
			Update: since version 1.2, the multi-tab version it is tricky to preserve the 
			original connection details. This led to a dangerous bug in which SQL intended
			to execute on one database was actually executed on another. See further comments
			around the build table method call
			*/
			this.Text += ": " + connInfo.Name;
			this.connectionString = dataSource.ConnectionString;
			this.dataSource = dataSource;
			this.textCommands.Paste(DataFormats.GetFormat("Text"));
		}

		private void BtnClose_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void BtnExecute_Click(object sender, EventArgs e)
		{
			ExecuteCommand();
		}
		private void BtnToggle_Click(object sender, EventArgs e)
		{
			OnToggle();
		}

		private void OnToggle()
		{
			// window size
			int toggleFactor = 5;  // splits 4:1
			int tabTitleAdjustment = 20; // this allows for tab control headings 
			int newSetting = splitContainer1.Size.Height / toggleFactor; // assumes shrinking the edit window
			// .. but if the edit window is the smaller section
			if (splitContainer1.SplitterDistance < splitContainer1.Size.Height / 2)
				newSetting = newSetting * (toggleFactor - 1) - tabTitleAdjustment;
			splitContainer1.SplitterDistance = newSetting;
		}

		private void ExecuteCommand()
		{
			/*
				27/03/2012 Stopgap bug fix.
				To prevent SQL being executed on the wrong database check the original connection
				string against the present one returned by the driver. If there is a difference 
				then object.
				
				A neater solution would be to inject the original connection into the driver
				and restore the current connection after the command has executed, but this 
				feels dangerous and hacky. While I figure out a better plan I'll just prevent
				accidents
			*/
			if (this.connectionString != this.dataSource.ConnectionString)
			{
				this.textMessages.Text = ReformatMessage(WRONG_CONNECTION_MESSAGE);
				this.tabControl1.SelectedIndex = 0;	// messages pane
				this.toolStripStatusMessage.Text = "Execution Blocked";
				return;
			}
			// work out whether this will return a data set
			string script = this.textCommands.SelectedText;
			// use everything if nothing is selected
			if (script.Length == 0)
				script = this.textCommands.Text;
			if (script.Length == 0)
				return; // do nothing if window is empty
			// 
			try
			{
				/*
					To deal with the query/command distinction require returned table to be decorated
					with extra info that contains the message
				*/
				this.toolStripStatusMessage.Text = "Working...";
				Command adhocCommand = new Command(Commands.Cmnd.Adhoc);
				ViewContext vc = new ViewContext(adhocCommand);
				vc.Command = adhocCommand;
				vc.FilterString = script; // hijack the filter string for the whole script
				// check connection info attached to the source.
				DataTable dt = this.dataSource.BuildTable(adhocCommand, vc);
				DataTableExtraInfoManager mgr = new DbView.DataTableExtraInfoManager(dt);
				string message = mgr.GetExtraInfo("MESSAGE", "");

				int rows = dt.Rows.Count;
				this.textMessages.Text = "Command completed";
				this.textMessages.Text += string.Format("\n{0}", message);

				this.dgResults.Visible = false; // added for render speed. Remove if it proves ugly
				this.dgResults.DataSource = null;
				this.dgResults.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
				this.dgResults.DefaultCellStyle.WrapMode = DataGridViewTriState.False;

				BindingSource bindSource = new BindingSource();
				// set the BindingSource DataSource
				bindSource.DataSource = dt;
				// set the DataGridView DataSource
				this.dgResults.DataSource = bindSource;
				// prevent edits unless user asks
				this.dgResults.ReadOnly = true;
				this.dgResults.Visible = true; // added for render speed. Remove if it proves ugly
				if (dt.Columns.Count == 0)
					this.tabControl1.SelectedIndex = 0;
				else
					this.tabControl1.SelectedIndex = 1;

				this.toolStripStatusMessage.Text = string.Format("Done: {0} rows", rows);
			}
			catch (Exception exc)
			{
				// be a little bit intelligent and helpful here.
				this.textMessages.Text = exc.Message;
				this.tabControl1.SelectedIndex = 0;
				this.toolStripStatusMessage.Text = "!Error";
			}
		}
		// unused for now.
		private string MakeScriptPart(String script)
		{
			int pos = script.IndexOf('\n');
			if (pos == -1) pos = script.Length;
			if (pos > 50)
				pos = 50;
			return script.Substring(0, pos) + "...";
		}
		private bool ReturnsData(String script)
		{
			// check for select
			if (script.ToUpper().IndexOf("SELECT ") == -1)
				return false;
			return true;
		}

		// on activate check for connection change and warn.
		private void TextCommands_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{
		}

		private void TextCommands_KeyUp(object sender, KeyEventArgs e)
		{
			if ((Control.ModifierKeys & Keys.Control) == Keys.Control && e.KeyCode == Keys.E)
			{
				ExecuteCommand();
				e.Handled = true;
			}
		}

		private void TextCommands_KeyDown(object sender, KeyEventArgs e)
		{
			if ((Control.ModifierKeys & Keys.Control) == Keys.Control && e.KeyCode == Keys.E)
			{
				// prevent centering
				e.Handled = true;
			}
		}

		private void BtnZoom_Click(object sender, EventArgs e)
		{
			string btnTextEnlarge = "&Enlarge";
			string btnTextRestore = "Restor&e";
			Button zoom = (Button)sender;
			string buttonText = zoom.Text;
			if (buttonText == btnTextRestore) // e n l a r g e
			{
				this.SetBounds(this.holdBounds.Left, this.holdBounds.Top, this.holdBounds.Width, this.holdBounds.Height);
				zoom.Text = btnTextEnlarge;
			}
			else
			{
				int margin = 20;
				this.holdBounds = this.Bounds;
				// get screen size
				Rectangle scr = Screen.PrimaryScreen.Bounds;
				// resize window
				this.SetBounds(1, 1, scr.Width - margin, scr.Height - margin);
				zoom.Text = btnTextRestore;
			}
		}

		private void BtnClear_Click(object sender, EventArgs e)
		{
			this.textCommands.Text = "";
		}

		private string ReformatMessage(String message)
		{
			return message.Replace("\r", "").Replace("_\n", " ");
		}

		const string WRONG_CONNECTION_MESSAGE = @"
I'm sorry, but this query or command cannot be executed. This is due to a limitation_
of the program. Since opening the Adhoc query window you have connected to a different_
database or switched tabs. You can still execute this command, but you need_
to reconnect or switch back to a tab that is connected to the same database that this_
window is connected to. You can see which one from the window caption.

If you genuinely intended to execute the SQL on the database that the current tab is connected_
to then open another adhoc query window, paste in the SQL and execute it from there.
";
	}
}
